#region --- License & Copyright Notice ---
/*
ConsoleFx CommandLine Processing Library

Copyright (c) 2006-2012 Jeevan James
All rights reserved.

The contents of this file are made available under the terms of the
Eclipse Public License v1.0 (the "License") which accompanies this
distribution, and is available at the following URL:
http://opensource.org/licenses/eclipse-1.0.txt

Software distributed under the License is distributed on an "AS IS" basis,
WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See the License for
the specific language governing rights and limitations under the License.

By using this software in any fashion, you are agreeing to be bound by the
terms of the License.
*/
#endregion

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;

using ConsoleFx.Parsers;

namespace ConsoleFx.Programs
{
    public abstract class UsageBuilder
    {
        private readonly Parser _parser;
        private object[] _assemblyAttributes;

        protected UsageBuilder(Parser parser)
        {
            _parser = parser;
        }

        public virtual StringBuilder GenerateFullUsage()
        {
            var sb = new StringBuilder();
            GenerateHeaderSection(sb);
            GenerateOptionsUsage(sb);
            GenerateFooterSection(sb);
            return sb;
        }

        public virtual void GenerateOptionsUsage(StringBuilder sb)
        {
        }

        protected virtual void GenerateHeaderSection(StringBuilder sb)
        {
        }

        protected virtual void GenerateFooterSection(StringBuilder sb)
        {
        }

        protected Parser Parser
        {
            get { return _parser; }
        }

        //Utility method to split a string into smaller strings of the specified length
        //TODO: Add support for splitting the string at correct word breaks
        protected static IEnumerable<string> SplitString(string str, int length)
        {
            int start = 0;
            int end = length - 1;
            while (start < str.Length)
            {
                yield return str.Substring(start, Math.Min(str.Length - start, end - start));
                start = end;
                end = start + length;
            }
        }

        #region Assembly properties
        protected string AssemblyTitle
        {
            get { return GetAssemblyAttribute<AssemblyTitleAttribute>(attr => attr.Title); }
        }

        protected string AssemblyDescription
        {
            get { return GetAssemblyAttribute<AssemblyDescriptionAttribute>(attr => attr.Description); }
        }

        protected string AssemblyCompany
        {
            get { return GetAssemblyAttribute<AssemblyCompanyAttribute>(attr => attr.Company); }
        }

        protected string AssemblyProduct
        {
            get { return GetAssemblyAttribute<AssemblyProductAttribute>(attr => attr.Product); }
        }

        protected string AssemblyCopyright
        {
            get { return GetAssemblyAttribute<AssemblyCopyrightAttribute>(attr => attr.Copyright); }
        }

        private string GetAssemblyAttribute<TAttr>(Func<TAttr, string> valueExtractor) where TAttr : Attribute
        {
            object attribute = AssemblyAttributes.FirstOrDefault(attr => attr.GetType() == typeof(TAttr));
            return attribute != null ? valueExtractor((TAttr)attribute) : null;
        }

        private IEnumerable<object> AssemblyAttributes
        {
            get { return _assemblyAttributes ?? (_assemblyAttributes = Assembly.GetEntryAssembly().GetCustomAttributes(true)); }
        }
        #endregion
    }
}